package com.bbva.kyfb.kyfbdaofiimpl;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.persistence.Query;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.NonUniqueObjectException;
import org.springframework.orm.jpa.JpaSystemException;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.bbva.jee.arq.spring.core.gce.ExcepcionEjecucionAplicacion;
import com.bbva.jee.arq.spring.core.log.I18nLog;
import com.bbva.jee.arq.spring.core.log.I18nLogFactory;
import com.bbva.kyfb.kyfbdaofi.IFirmasDao;
import com.bbva.kyfb.kyfbdto.firmas.bo.FicheroInfo;
import com.bbva.kyfb.kyfbdto.firmas.errores.Errores_kyfb_servicios;
import com.bbva.kyfb.kyfbdto.firmas.filtros.FiltroFicheros;
import com.bbva.kyfb.kyfbjpatlbh.dominiotlbh.Ttlsbfua;
import com.bbva.kyfb.kyfbjpatlbh.dominiotlbh.Ttlsbont;
import com.bbva.kyfb.kyfbjpatlsb.dominiotlsb.Ttlsbffs;
import com.bbva.kyfb.kyfbjpatlsb.dominiotlsb.Ttlsbfrf;
import com.bbva.kyfb.kyfbutils.constantes.ConstantesFO;
import com.bbva.kyfb.kyfbutils.constantes.UtilFO;
import com.bbva.kyfb.kyfbutils.dao.DaoUtils;
import com.bbva.kyfb.kyfbutils.host.Constants;

/**
 * The Class ServicioFirmasDaoImpl.
 */
@Component(value = "servicioFirmasDao")
@SuppressWarnings("unchecked")
public class ServicioFirmasDaoImpl implements IFirmasDao {

	/** The em. */
	@PersistenceContext(unitName = "persistenceUnitTLBH")
	private transient EntityManager em;

	/** The em tlsb. */
	@PersistenceContext(unitName = "persistenceUnitTLSB")
	private transient EntityManager emTLSB;


	/** Variable LOG. */
	private static final I18nLog LOG = I18nLogFactory
			.getLogI18n(ServicioFirmasDaoImpl.class);

	/**
	 * {@inheritDoc}
	 */
	@Override
	@Transactional(value="tlbh")
	public List<Object[]> findComponentesPdteReferenciaTimFichero(final String codClienteCash, final String codigoAplicacion, final FiltroFicheros filtro, final boolean ordenante, final String[] timFicheros) {

		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		StringBuilder filteredQuery = new StringBuilder(getQueryBaseHost(codClienteCash,codigoAplicacion,filtro,ordenante,timFicheros,paramValues));

		if (filtro != null && !StringUtils.isEmpty(filtro.getOrdenarPor())) {
			//Paginacion si procede (Por defecto desde 0 hasta 0) con orden si procede (Por defecto ordenado por TIM_FICHERO (Fecha de creacion))
			if(filtro.getPaginarDesde()>=0 && filtro.getNumElementos()>0) {
				final Object pagParams[] = new Object[]{filtro.getPaginarDesde(),filtro.getNumElementos(),	//2 primeros son parametros normales
						filtro.getOrdenarPor(),filtro.getModoOrdenacion()}; //2 segundos son para concatenar directamente

				filteredQuery=DaoUtils.addPaginate(filteredQuery, pagParams, paramValues);
			}else{
				//Orden si procede (Por defecto ordenado por TIM_FICHERO (Fecha de creacion))
				final String ordParams[] = new String[]{filtro.getOrdenarPor(),filtro.getModoOrdenacion()};
				filteredQuery.append(DaoUtils.addOrderSimple(ordParams));
			}
		}

		final Query q = em.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		final List<Object[]> resultado = q.getResultList();

		DaoUtils.atLeastOneRecord(resultado);

		return resultado;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@Transactional(value="tlbh")
	public int countComponentesPdteReferenciaTimFichero(final String codClienteCash, final String codigoAplicacion, final FiltroFicheros filtro, final boolean ordenante, final String[] timFicheros) {

		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQueryCount = new StringBuilder("SELECT COUNT(*) AS TOTAL FROM (");
		filteredQueryCount.append(getQueryBaseHost(codClienteCash,codigoAplicacion,filtro,ordenante,timFicheros,paramValues)).append(")");

		final Query q = em.createNativeQuery(filteredQueryCount.toString());
		DaoUtils.addQueryParams(paramValues, q);

		return ((Number)q.getSingleResult()).intValue();
	}

	/**
	 * Gets the query base Host.
	 *
	 * @param codClienteCash the cod cliente cash
	 * @param filtro the filtro
	 * @param ordenante the ordenante
	 * @param paramValues the param values
	 * @return the query base
	 */
	private String getQueryBaseHost(final String codClienteCash, final String codigoAplicacion, final FiltroFicheros filtro, final boolean ordenante, final String[] timFicheros, final Map<Integer, Object> paramValues){

		final StringBuilder filteredQuery = new StringBuilder("SELECT DISTINCT S.QNU_NUMITEM AS QNU_NUMITEM, S.TIM_FICHERO AS TIM_FICHERO, ");

		filteredQuery.append("VARCHAR(C.DES_NOMFICH) AS DES_NOMFICH , VARCHAR(S.DES_ASUNACCE) AS DES_ASUNACCE, C.QNU_TOTREGIS AS QNU_TOTREGIS, ");
		filteredQuery.append("C.QTY_TOTIMP AS QTY_TOTIMP, VARCHAR(S.COD_ESTADODS) AS COD_ESTADODS, VARCHAR(S.COD_CLASEORD) AS COD_CLASEORD, ");
		filteredQuery.append("S.QNU_PESOFIR AS QNU_PESOFIR, VARCHAR(S.COD_IDORDEN) AS COD_IDORDEN, VARCHAR(C.FEC_PROCESCA) AS FEC_PROCESCA,VARCHAR(D.COD_ABREVIAT) AS COD_ABREVIAT,S.COD_SERCRUBD AS COD_SERCRUBD, S.IMP_MAXREG AS IMP_MAXREG, VARCHAR(CLO.XTI_MODOORDE) AS XTI_MODOORDE ");
		filteredQuery.append("FROM TLSB.TTLSBCAB C INNER JOIN TLSB.TTLSBSFO S ON (S.COD_CLIECASH = C.COD_CLIECASH ");
		filteredQuery.append("AND S.COD_CLASEORD = C.COD_CLASEORD ");
		filteredQuery.append("AND S.COD_IDORDEN = C.COD_IDORDEN) ");
		filteredQuery.append("INNER JOIN TLSB.TTLSBDIV D ON (C.COD_DIISOALF = D.COD_DIISOALF OR C.COD_DIISOALF = D.COD_ABREVIAT) ");
		filteredQuery.append("INNER JOIN TLSB.TTLSBCLO CLO ON (CLO.COD_CLASEORD = C.COD_CLASEORD) ");

		if (codigoAplicacion != null) {
			filteredQuery.append("INNER JOIN TLSB.TTLSBPPA PPA ON (PPA.COD_OBJF = C.COD_CLASEORD)");
		}

		filteredQuery.append(DaoUtils.addInClause("S.TIM_FICHERO", timFicheros, paramValues, true, null));

		if (ordenante) {
			filteredQuery.append("INNER JOIN TLSB.TTLSBFUA F ON (F.COD_CLIECASH = C.COD_CLIECASH ");
			filteredQuery.append("AND F.COD_CLASEORD = C.COD_CLASEORD AND F.COD_IDORDEN = C.COD_IDORDEN) ");
		}

		if (codClienteCash != null) {
			filteredQuery.append(DaoUtils.addFilter("S.COD_CLIECASH", "=", codClienteCash, paramValues, true, null));
		}

		filteredQuery.append(DaoUtils.addInClause("S.COD_ESTADODS", new String[]{"PF", "FP", "PA"}, paramValues, true, null));

		if (codigoAplicacion != null) {
			filteredQuery.append(DaoUtils.addFilter("PPA.COD_APLICACI","=", codigoAplicacion, paramValues, true, null));
		}

		if (filtro != null) {
			filteredQuery.append(DaoUtils.addFilter("C.FEC_PROCESCA", ">=", filtro.getFechaProcesoDesde(), paramValues, true, new SimpleDateFormat("yyyyMMdd")));
			filteredQuery.append(DaoUtils.addFilter("C.FEC_PROCESCA", "<=", filtro.getFechaProcesoHasta(), paramValues, true, new SimpleDateFormat("yyyyMMdd")));
			filteredQuery.append(DaoUtils.addInClause("C.COD_CLASEORD", filtro.getClaseOrden(), paramValues, true, null));
			filteredQuery.append(DaoUtils.addFilter("F.COD_USUARIO", "=", filtro.getCodUsuario(), paramValues, true, null));
			filteredQuery.append(DaoUtils.addInClause("D.COD_ABREVIAT", filtro.getDivisas(), paramValues, true, null));
			filteredQuery.append(DaoUtils.addFilter("C.COD_IDORDEN", "=", filtro.getIdOrden(), paramValues, true, null));
			filteredQuery.append(DaoUtils.addInClause("S.COD_ESTADODS", filtro.getEstados(), paramValues, true, null));
		}
		return filteredQuery.toString();
	}

	/* (non-Javadoc)
	 * @see com.bbva.kyfb.kyfbdaofi.IFirmasDao#getTotalComponentesPdtesReferenciaHost(java.lang.String, com.bbva.kyfb.kyfbdto.firmas.filtros.FiltroFicheros, boolean,String[])
	 */
	@Override
	public int getTotalComponentesPdtesReferenciaHost(final String codClienteCash, final String codigoAplicacion, final FiltroFicheros filtro, final boolean ordenante, final String[] timFicheros) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQueryCount = new StringBuilder("SELECT COUNT(*) AS TOTAL FROM (");
		filteredQueryCount.append(getQueryBaseHost(codClienteCash,codigoAplicacion,filtro,ordenante,timFicheros,paramValues)).append(")");

		final Query q = em.createNativeQuery(filteredQueryCount.toString());
		DaoUtils.addQueryParams(paramValues, q);

		return ((Number)q.getSingleResult()).intValue();

	}

	/**
	 * Gets the query base.
	 *
	 * @param codClienteCash the cod cliente cash
	 * @param filtro the filtro
	 * @param ordenante the ordenante
	 * @param paramValues the param values
	 * @return the query base
	 */
	private String getQueryBase(final String codClienteCash,final String codigoAplicacion, final FiltroFicheros filtro, final boolean ordenante, final Map<Integer, Object> paramValues){
		final StringBuilder filteredQuery = new StringBuilder("SELECT DISTINCT S.QNU_NUMITEM, S.TIM_FICHERO, ");

		filteredQuery.append("VARCHAR(C.DES_NOMFICH) AS DES_NOMFICH, VARCHAR(S.DES_ASUNACCE) AS DES_ASUNACCE, C.QNU_TOTREGIS AS QNU_TOTREGIS, ");
		filteredQuery.append("C.QTY_TOTIMP AS QTY_TOTIMP, VARCHAR(S.COD_ESTADODS) AS COD_ESTADODS, VARCHAR(S.COD_CLASEORD) AS COD_CLASEORD, ");
		filteredQuery.append("S.QNU_PESOFIR AS QNU_PESOFIR, VARCHAR(S.COD_IDORDEN) AS COD_IDORDEN, VARCHAR(C.FEC_PROCESCA) AS FEC_PROCESCA,VARCHAR(D.COD_ABREVIAT) AS COD_ABREVIAT, S.COD_SERCRUBD AS COD_SERCRUBD, S.IMP_MAXREG AS IMP_MAXREG, VARCHAR(CLO.XTI_MODOORDE) AS XTI_MODOORDE ");
		filteredQuery.append("FROM TLSB.TTLSBCAB C INNER JOIN TLSB.TTLSBSFO S ON (S.COD_CLIECASH = C.COD_CLIECASH ");
		filteredQuery.append("AND S.COD_CLASEORD = C.COD_CLASEORD ");
		filteredQuery.append("AND S.COD_IDORDEN = C.COD_IDORDEN) ");
		filteredQuery.append("INNER JOIN TLSB.TTLSBDIV D ON (C.COD_DIISOALF = D.COD_DIISOALF OR C.COD_DIISOALF = D.COD_ABREVIAT) ");
		filteredQuery.append("INNER JOIN TLSB.TTLSBCLO CLO ON (CLO.COD_CLASEORD = C.COD_CLASEORD) ");

		if (codigoAplicacion != null) {
			filteredQuery.append("INNER JOIN TLSB.TTLSBPPA PPA ON (PPA.COD_OBJF = C.COD_CLASEORD)");
		}

		if (ordenante) {
			filteredQuery.append("INNER JOIN TLSB.TTLSBFUA F ON (F.COD_CLIECASH = C.COD_CLIECASH ");
			filteredQuery.append("AND F.COD_CLASEORD = C.COD_CLASEORD AND F.COD_IDORDEN = C.COD_IDORDEN) ");
		}

		if (codClienteCash != null) {
			filteredQuery.append(DaoUtils.addFilter("C.COD_CLIECASH", "=", codClienteCash, paramValues, null, null));
			filteredQuery.append(DaoUtils.addInClause("S.COD_ESTADODS", new String[]{"PF", "FP", "PA"}, paramValues, true, null));
		} else {
			filteredQuery.append(DaoUtils.addInClause("S.COD_ESTADODS", new String[]{"PF", "FP", "PA"}, paramValues, null, null));
		}
		if (codigoAplicacion != null) {
			filteredQuery.append(DaoUtils.addFilter("PPA.COD_APLICACI","=", codigoAplicacion, paramValues, true, null));
		}

		if (filtro != null) {
			filteredQuery.append(DaoUtils.addFilter("C.FEC_PROCESCA", ">=", filtro.getFechaProcesoDesde(), paramValues, true, new SimpleDateFormat("yyyyMMdd")));
			filteredQuery.append(DaoUtils.addFilter("C.FEC_PROCESCA", "<=", filtro.getFechaProcesoHasta(), paramValues, true, new SimpleDateFormat("yyyyMMdd")));
			filteredQuery.append(DaoUtils.addInClause("C.COD_CLASEORD", filtro.getClaseOrden(), paramValues, true, null));
			filteredQuery.append(DaoUtils.addFilter("F.COD_USUARIO", "=", filtro.getCodUsuario(), paramValues, true, null));
			filteredQuery.append(DaoUtils.addFilter("C.QTY_TOTIMP", ">=", filtro.getImporteDesde(), paramValues, true, null));
			filteredQuery.append(DaoUtils.addFilter("C.QTY_TOTIMP", "<=", filtro.getImporteHasta(), paramValues, true, null));
			filteredQuery.append(DaoUtils.addInClause("D.COD_ABREVIAT", filtro.getDivisas(), paramValues, true, null));
			filteredQuery.append(DaoUtils.addFilter("C.COD_IDORDEN", "=", filtro.getIdOrden(), paramValues, true, null));
			filteredQuery.append(DaoUtils.addInClause("S.COD_ESTADODS", filtro.getEstados(), paramValues, true, null));
			filteredQuery.append(DaoUtils.addFilter("S.TIM_FICHERO", ">=", filtro.getFechaCreacionDesde(), paramValues, true, null));
			filteredQuery.append(DaoUtils.addFilter("S.TIM_FICHERO", "<", UtilFO.addOrsubtractsDate(filtro.getFechaCreacionHasta(), 1), paramValues, true, null));
		}
		return filteredQuery.toString();
	}

	/* (non-Javadoc)
	 * @see com.bbva.kyfb.kyfbdaofi.IFirmasDao#getTotalComponentesPdtesReferencia(java.lang.String, com.bbva.kyfb.kyfbdto.firmas.filtros.FiltroFicheros, boolean)
	 */
	@Override
	public int getTotalComponentesPdtesReferencia(final String codClienteCash, final String codigoAplicacion, final FiltroFicheros filtro, final boolean ordenante) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQueryCount = new StringBuilder("SELECT COUNT(*) AS TOTAL FROM (");
		filteredQueryCount.append(getQueryBase(codClienteCash,codigoAplicacion,filtro,ordenante,paramValues)).append(")");

		final Query q = em.createNativeQuery(filteredQueryCount.toString());
		DaoUtils.addQueryParams(paramValues, q);

		return ((Number)q.getSingleResult()).intValue();

	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@Transactional(value="tlbh")
	public List<Object[]> findComponentesPdteReferencia(final String codClienteCash, final String codigoAplicacion, final FiltroFicheros filtro, final boolean ordenante) {

		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		StringBuilder filteredQuery = new StringBuilder(getQueryBase(codClienteCash,codigoAplicacion,filtro,ordenante,paramValues));

		if (filtro != null && !StringUtils.isEmpty(filtro.getOrdenarPor())) {
			//Paginacion si procede (Por defecto desde 0 hasta 0) con orden si procede (Por defecto ordenado por TIM_FICHERO (Fecha de creacion))
			if(filtro.getPaginarDesde()>=0 && filtro.getNumElementos()>0) {
				final Object pagParams[] = new Object[]{filtro.getPaginarDesde(),filtro.getNumElementos(),	//2 primeros son parametros normales
						filtro.getOrdenarPor(),filtro.getModoOrdenacion()}; //2 segundos son para concatenar directamente

				filteredQuery=DaoUtils.addPaginate(filteredQuery, pagParams, paramValues);
			}else{
				//Orden si procede (Por defecto ordenado por TIM_FICHERO (Fecha de creacion))
				final String ordParams[] = new String[]{filtro.getOrdenarPor(),filtro.getModoOrdenacion()};
				filteredQuery.append(DaoUtils.addOrderSimple(ordParams));
			}
		}

		final Query q = em.createNativeQuery(filteredQuery.toString());//.setMaxResults(10).setFirstResult(0);
		DaoUtils.addQueryParams(paramValues, q);

		final List<Object[]> resultado = q.getResultList();

		DaoUtils.atLeastOneRecord(resultado);

		return resultado;
	}

	/**
	 * {@inheritDoc}
	 */

	@Override
	@Transactional(value="tlbh")
	public List<Object[]> findComponentesPdteReferenciaUsuario(final String codClienteCash, final String codigoAplicacion, final FiltroFicheros filtro, final boolean ordenante) throws ExcepcionEjecucionAplicacion {

		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder(getQueryBase(codClienteCash,codigoAplicacion,filtro,ordenante,paramValues));

		if (filtro != null && !StringUtils.isEmpty(filtro.getOrdenarPor())) {
			//Orden si procede (Por defecto ordenado por TIM_FICHERO (Fecha de creacion))
			final String ordParams[]={filtro.getOrdenarPor(),filtro.getModoOrdenacion()};
			filteredQuery.append(DaoUtils.addOrderSimple(ordParams));

		}

		final Query q = em.createNativeQuery(filteredQuery.toString());//.setMaxResults(10).setFirstResult(0);
		DaoUtils.addQueryParams(paramValues, q);

		final List<Object[]> resultado = q.getResultList();

		DaoUtils.atLeastOneRecord(resultado);

		return resultado;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@Transactional(value="tlbh")
	public List<Ttlsbfua> findAuditoriaComponentePdte(final String codClienteCash, final String claseOrden, final String idOrden, final String[] estados) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("SELECT F.* FROM TLSB.TTLSBFUA F LEFT JOIN TLSB.TTLSBACU A ON F.COD_ACCION = A.COD_ACCION ");

		filteredQuery.append(DaoUtils.addFilter("F.COD_CLIECASH", "=", codClienteCash, paramValues, null, null));
		filteredQuery.append(DaoUtils.addFilter("F.COD_CLASEORD", "=", claseOrden, paramValues, true, null));
		filteredQuery.append(DaoUtils.addFilter("F.COD_IDORDEN", "=", idOrden, paramValues, true, null));
		filteredQuery.append(DaoUtils.addInClause("F.COD_ESTADFIC", new String[]{"019", "020", "024"}, paramValues, true, null));
		filteredQuery.append(DaoUtils.addInClause("F.COD_ESTADFIC", estados, paramValues, true, null));

		//Orden (Por defecto ordenado por F._AUD_MODIFIC (fecha) y F.FEC_ACCION2 (minutos))
		final String ordParams[]={UtilFO.getCampoOrden(null, ConstantesFO.PET_AUDITORIA),null};
		filteredQuery.append(DaoUtils.addOrderSimple(ordParams));

		final Query q = em.createNativeQuery(filteredQuery.toString(), Ttlsbfua.class);
		DaoUtils.addQueryParams(paramValues, q);

		final List<Ttlsbfua> resultado = q.getResultList();
		DaoUtils.atLeastOneRecord(resultado);

		return resultado;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@Transactional(value="tlbh")
	public List<Object[]> findFirmablesAplicacion(final String codApp) {
		// TODO: ERRORES
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("SELECT VARCHAR(COD_OBJF), VARCHAR(DES_OBJF), VARCHAR(XSN_FIRMABLE), VARCHAR(DES_URLEJE), VARCHAR(DES_URLAUD) , VARCHAR(XSN_MSGAVS), VARCHAR(COD_MSGAVS) FROM TLSB.TTLSBPPA ");
		filteredQuery.append(DaoUtils.addFilter("COD_APLICACI", "=", codApp, paramValues, null, null));
		filteredQuery.append(DaoUtils.addFilter("XSN_FIRMABLE", "=", "S", paramValues, true, null));

		final Query q = em.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		final List<Object[]> resultado = q.getResultList();
		DaoUtils.atLeastOneRecord(resultado);

		return resultado;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@Transactional(value="tlbh")
	public List<Object[]> findFirmablesAplicacionFirm(final String codApp) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("SELECT VARCHAR(COD_OBJF) FROM TLSB.TTLSBPPA ");
		filteredQuery.append(DaoUtils.addFilter("COD_APLICACI", "=", codApp, paramValues, null, null));
		filteredQuery.append(DaoUtils.addFilter("XSN_FIRMABLE", "=", "S", paramValues, true, null));

		final Query q = em.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		final List<Object[]> resultado = q.getResultList();
		DaoUtils.atLeastOneRecord(resultado);

		return resultado;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@Transactional(value="tlbh")
	public List<Object[]> findHusoHorario(final String[] claseOrd) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("SELECT VARCHAR(COD_CLASEORD), VARCHAR(XTI_CORTE), HMS_CORTE, VARCHAR(COD_SERVIMOD) FROM TLSB.TTLSBCLO ");
		filteredQuery.append(DaoUtils.addInClause("COD_CLASEORD", claseOrd, paramValues, null, null));

		final Query q = em.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		final List<Object[]> resultado = q.getResultList();
		DaoUtils.atLeastOneRecord(resultado);

		return resultado;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@Transactional(value="tlbh")
	public List<Object[]> findValidacion(final String codValidacion) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("SELECT DES_URLVAL FROM TLSB.TTLSBVAL ");
		filteredQuery.append(DaoUtils.addFilter("COD_VALI", "=", codValidacion, paramValues, null, null));

		final Query q = em.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		final List<Object[]> resultado = q.getResultList();
		DaoUtils.atLeastOneRecord(resultado);

		return resultado;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@Transactional(value="tlbh")
	public void updateEstadoFichero(final String estado, final String codClienteCash, final String claseOrden, final String idOrden) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("UPDATE TLSB.TTLSBCAB SET COD_ESTACASH = ?1 ");
		paramValues.put(1, estado);

		filteredQuery.append(DaoUtils.addFilter("COD_CLIECASH", "=", codClienteCash, paramValues, null, null));
		filteredQuery.append(DaoUtils.addFilter("COD_CLASEORD", "=", claseOrden, paramValues, true, null));
		filteredQuery.append(DaoUtils.addFilter("COD_IDORDEN", "=", idOrden, paramValues, true, null));

		final Query q = em.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		final int resultado = q.executeUpdate();
		DaoUtils.oneRecordUpdated(resultado);
		em.flush();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@Transactional(value="tlbh")
	public void updatePesoEstadoFirma(final String estado, final Double peso, final String codClienteCash, final String claseOrden, final String idOrden) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("UPDATE TLSB.TTLSBSFO SET COD_ESTADODS = ?1 , QNU_PESOFIR = ?2 ");
		paramValues.put(1, estado);
		paramValues.put(2, peso);

		filteredQuery.append(DaoUtils.addFilter("COD_CLIECASH", "=", codClienteCash, paramValues, null, null));
		filteredQuery.append(DaoUtils.addFilter("COD_CLASEORD", "=", claseOrden, paramValues, true, null));
		filteredQuery.append(DaoUtils.addFilter("COD_IDORDEN", "=", idOrden, paramValues, true, null));

		final Query q = em.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		final int resultado = q.executeUpdate();
		DaoUtils.oneRecordUpdated(resultado);
		em.flush();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@Transactional(value="tlsb")
	public void insertFFS(final Ttlsbffs firmante) {
		// Insertamos en la tabla FFS, si hay excepcion, se eleva a capas superiores
		firmante.persist();
		firmante.flush();
		LOG.info("ServicioFirmasDaoImpl.insertFFS - Se inserta correctamente en la FFS");
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void insertFirmante(final Ttlsbffs firmante) {
		try {
			firmante.persist();
			firmante.flush();
			//Si da error
			// el firmante existe para el fichero, por lo que es un fichero
			// antiguo y realizamos el update.
		} catch (final PersistenceException pe) {
			updateFirmateToFirmado(firmante);
		} catch (final NonUniqueObjectException nuoe) {
			updateFirmateToFirmado(firmante);
		} catch (final JpaSystemException jse) {
			updateFirmateToFirmado(firmante);
		}

	}


	/**
	 * {@inheritDoc}
	 */
	@Override
	public void insertAuditoria(final Ttlsbfua aud) {
		aud.persist();
		aud.flush();
	}

	/**
	 * Update firmate to firmado.
	 *
	 * @param firmante the firmante
	 */
	@Transactional(value="tlsb")
	private void updateFirmateToFirmado(final Ttlsbffs firmante) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("UPDATE TLSB.TTLSBFFS SET XSN_FIRMADO = '" + firmante.getXsnFirmado() + "'");
		filteredQuery.append(DaoUtils.addFilter("QNU_NUMITEM", "=", firmante.getId().getQnuNumitem(), paramValues, null, null));
		filteredQuery.append(DaoUtils.addFilter("TIM_FICHERO", "=", firmante.getId().getTimFichero(), paramValues, true, null));
		filteredQuery.append(DaoUtils.addFilter("COD_USUARIO", "=", firmante.getId().getCodUsuario(), paramValues, true, null));

		final Query q = emTLSB.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		final int resultado = q.executeUpdate();
		DaoUtils.oneRecordUpdated(resultado);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@Transactional(value="tlsb")
	public void updateNumAleatorioFFS(final Ttlsbffs firmante) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("UPDATE TLSB.TTLSBFFS SET COD_NUMALEAT = '"+ firmante.getCodNumaleat() +"' ");
		filteredQuery.append(DaoUtils.addFilter("QNU_NUMITEM", "=", firmante.getId().getQnuNumitem(), paramValues, null, null));
		filteredQuery.append(DaoUtils.addFilter("TIM_FICHERO", "=", firmante.getId().getTimFichero(), paramValues, true, null));
		filteredQuery.append(DaoUtils.addFilter("COD_USUARIO", "=", firmante.getId().getCodUsuario(), paramValues, true, null));

		final Query q = emTLSB.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		LOG.info("ServicioFirmasDaoImpl.updateNumAleatorioFFS - Se realiza el Update en la FFS");
		LOG.info("ServicioFirmasDaoImpl.updateNumAleatorioFFS - QNU_NUMITEM: " + paramValues.get(1));
		LOG.info("ServicioFirmasDaoImpl.updateNumAleatorioFFS - TIM_FICHERO: " + paramValues.get(2));
		LOG.info("ServicioFirmasDaoImpl.updateNumAleatorioFFS - COD_USUARIO: " + paramValues.get(3));

		final int resultado = q.executeUpdate();
		LOG.info("ServicioFirmasDaoImpl.updateNumAleatorioFFS - Registros actualizados: "+ resultado);
		DaoUtils.oneRecordUpdated(resultado);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void insertAuditoriaFirma(final Ttlsbfua fua){
		fua.persist();
		fua.flush();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void insertDisclaimer(final Ttlsbont ont){
		ont.persist();
		ont.flush();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@Transactional(value="tlsb")
	public void updateBit(final String codCanal, final String bancoInt, final String logon, final BigDecimal numItem) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("UPDATE BDBZ.TBDBZBIT SET COD_LOGONAPL = 'ORDENESCSB', XTI_BUZON = 'A', AUD_USUARIO = CURRENT USER, AUD_FMODIFIC = CURRENT DATE ");
		filteredQuery.append(DaoUtils.addFilter("COD_CANALDI", "=", codCanal, paramValues, null, null));
		filteredQuery.append(DaoUtils.addFilter("COD_BANCOINT", "=", bancoInt, paramValues, true, null));
		filteredQuery.append(DaoUtils.addFilter("COD_LOGONAPL", "=", logon, paramValues, true, null));
		filteredQuery.append(DaoUtils.addFilter("QNU_NUMITEM", "=", numItem, paramValues, true, null));


		final Query q = emTLSB.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		final int resultado = q.executeUpdate();
		DaoUtils.oneRecordUpdated(resultado);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@Transactional(value="tlsb")
	public void updateBitDelete(final String codCanal, final String bancoInt, final String logon, final BigDecimal numItem) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("UPDATE BDBZ.TBDBZBIT SET COD_LOGONAPL = 'BORRADO', XTI_BUZON = 'A', AUD_USUARIO = CURRENT_USER, AUD_FMODIFIC = CURRENT_DATE ");
		filteredQuery.append(DaoUtils.addFilter("COD_CANALDI", "=", Integer.valueOf(codCanal), paramValues, null, null));
		filteredQuery.append(DaoUtils.addFilter("COD_BANCOINT", "=", Integer.valueOf(bancoInt), paramValues, true, null));
		// filteredQuery.append(DaoUtils.addFilter("COD_LOGONAPL", "=", logon, paramValues, true, null));
		filteredQuery.append(DaoUtils.addFilter("QNU_NUMITEM", "=", numItem, paramValues, true, null));


		final Query q = emTLSB.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);
		final int resultado = q.executeUpdate();
		DaoUtils.oneRecordUpdated(resultado);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@Transactional(value="tlsb")
	public String findEOOByOrd(final String tipoOrden, final String campo) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("SELECT VARCHAR(COD_CAMPOORD) FROM TLSB.TTLSBEOO ");
		filteredQuery.append(DaoUtils.addFilter("COD_TIPORD", "=", tipoOrden, paramValues, null, null));
		filteredQuery.append(DaoUtils.addFilter("DES_CAMPOLAR", "=", campo, paramValues, true, null));

		final Query q = emTLSB.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		return (String) q.getSingleResult();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@Transactional(value="tlsb")
	public String findOOLById(final double identificador) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("SELECT VARCHAR(DES_ORDENOL) FROM TLSB.TTLSBOOL ");
		filteredQuery.append(DaoUtils.addFilter("QNU_NUMITEM", "=", identificador, paramValues, null, null));

		final Query q = emTLSB.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		return (String)q.getSingleResult();

	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@Transactional(value="tlsb")
	public List<Object[]> findProductoByCodProdAndCodIdom(final Integer codigoProducto, final Integer codigoIdioma) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("SELECT COD_CODPROD, COD_FAMILIA, COD_SUBFAMIL, XTI_VENTA, DES_PROD, AUD_USUARIO, ");
		filteredQuery.append("AUD_FMODIFIC, COD_IDIOMA FROM TLNE.TTLNEMFD ");
		filteredQuery.append(DaoUtils.addFilter("COD_CODPROD", "=", codigoProducto, paramValues, null, null));
		filteredQuery.append(DaoUtils.addFilter("COD_IDIOMA", "=", codigoIdioma, paramValues, true, null));

		final Query q = emTLSB.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		//TODO: Esta no lleva la comprobacion de al menos un resultado, es correcto?

		return q.getResultList();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@Transactional(value="tlsb")
	public void deleteFirmantes(final String qnuItem, final Date timFichero) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("DELETE FROM TLSB.TTLSBFFS ");
		filteredQuery.append(DaoUtils.addFilter("QNU_NUMITEM", "=", qnuItem, paramValues, null, null));
		filteredQuery.append(DaoUtils.addFilter("TIM_FICHERO", "=", timFichero, paramValues, true, null));

		final Query q = emTLSB.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);
		//TODO: Hay un problema con el timestamp, los Date de Java y el UPDATE de base de datos por TIM_FICHERO
		q.executeUpdate();
		// Comentamos porque no hay que comprobar que el DELETE borre resultados
		// DaoUtils.oneRecordUpdated(resultado);
		emTLSB.flush();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@Transactional(value="tlbh")
	public List<Object[]> findObjetosFirmablesPorAplicacion(final String codAplicaci) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("SELECT VARCHAR(COD_OBJF), VARCHAR(COD_PAISOALF), VARCHAR(DES_OBJF), VARCHAR(XSN_FIRMABLE), ");
		filteredQuery.append("VARCHAR(DES_URLEJE), VARCHAR(DES_URLAUD),VARCHAR(DES_URLDET), ");
		filteredQuery.append("VARCHAR(XSN_FDSENV), VARCHAR(XSN_FDSREC) FROM TLSB.TTLSBPPA ");
		filteredQuery.append(DaoUtils.addFilter("COD_APLICACI", "=", codAplicaci, paramValues, null, null));

		final Query q = em.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		final List<Object[]> resultado = q.getResultList();
		DaoUtils.atLeastOneRecord(resultado);

		return resultado;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@Transactional(value="tlbh")
	public Map<String, String> findCodProductoByClaseOrd(final String claseOrd) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("SELECT VARCHAR(COD_CLASEORD), VARCHAR(COD_SERVIMOD) FROM TLSB.TTLSBCLO ");
		filteredQuery.append(DaoUtils.addFilter("COD_CLASEORD", "=", claseOrd, paramValues, null, null));

		final Query q = em.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		final List<Object[]> datos = q.getResultList();
		final Map<String, String> resultado = new HashMap<String, String>();

		for (final Object[] dato : datos) {
			resultado.put((String) dato[0], (String) dato[1]);
		}
		DaoUtils.atLeastOneRecord(resultado);

		return resultado;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@Transactional(value="tlbh")
	public Map<String, String> findClaseOrdByCodProducto(final String[] codServicios, final String codCanal, final String codBancoInt) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("SELECT DISTINCT VARCHAR(TTLSBCLO.COD_CLASEORD), VARCHAR(TTLSBCLO.COD_SERVIMOD) FROM TLSB.TTLSBCLO TTLSBCLO, TLSB.TTLSBOGP TTLSBOGP");
		filteredQuery.append(DaoUtils.addInClause("COD_SERVIMOD", codServicios, paramValues, null, null));
		filteredQuery.append(DaoUtils.addFilter("TTLSBOGP.COD_CANALDI", "=", Integer.valueOf(codCanal), paramValues, true, null));
		filteredQuery.append(DaoUtils.addFilter("TTLSBOGP.COD_BANCOINT", "=", Integer.valueOf(codBancoInt), paramValues, true, null));
		//filteredQuery.append(DaoUtils.addFilter("TTLSBOGP.COD_BANCOPR", "=", 1, paramValues, true, null));
		//filteredQuery.append(DaoUtils.addFilter("TTLSBOGP.COD_PRODSERV", "=", 1380, paramValues, true, null));
		//filteredQuery.append(DaoUtils.addFilter("TTLSBOGP.COD_SUBPRODU", "=", 0, paramValues, true, null));
		filteredQuery.append(" AND TTLSBCLO.COD_CLASEORD = TTLSBOGP.COD_CLASEORD");
		filteredQuery.append(" AND (TTLSBCLO.XTI_MODOORDE = 'O' OR (TTLSBCLO.XTI_MODOORDE = 'F' AND TTLSBCLO.XTI_ENVRECEP IN ('E','X','A')))");

		final Query q = em.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		final List<Object[]> datos = q.getResultList();
		final Map<String, String> resultado = new HashMap<String, String>();

		for (final Object[] dato : datos) {
			resultado.put((String) dato[0], (String) dato[1]);
		}
		DaoUtils.atLeastOneRecord(resultado);

		return resultado;
	}

	/**
	 * {@inheritDoc}
	 */

	@Override
	public List<Object[]> findFirmasRealizas(final String idOrden, final String tipoOrden, final String codClienteCash) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final List<BigDecimal> datos = findFirmasRealizadasSfo(idOrden, tipoOrden,
				codClienteCash, paramValues);

		final BigDecimal[] qnuItems = new BigDecimal[datos.size()];
		for (int i=0; i<datos.size();i++) {

			qnuItems[i] =  datos.get(i);
		}

		return findFirmasRealizasByNumItems(qnuItems);
	}


	/**
	 * Find firmas realizadas sfo.
	 *
	 * @param idOrden the id orden
	 * @param tipoOrden the tipo orden
	 * @param codClienteCash the cod cliente cash
	 * @param paramValues the param values
	 * @return the list
	 */
	@Transactional(value="tlbh")
	private List<BigDecimal> findFirmasRealizadasSfo(final String idOrden, final String tipoOrden, final String codClienteCash, final Map<Integer, Object> paramValues) {
		final StringBuilder filteredQuery = new StringBuilder();

		//filteredQuery.append("SELECT VARCHAR(F.COD_USUARIO), VARCHAR(F.XTI_PODFIR) FROM TLSB.TTLSBFFS F ");
		filteredQuery.append("SELECT S.QNU_NUMITEM FROM TLSB.TTLSBSFO S ");
		filteredQuery.append(DaoUtils.addFilter("S.COD_CLIECASH", "=", codClienteCash, paramValues, null, null));
		filteredQuery.append(DaoUtils.addFilter("S.COD_CLASEORD", "=", tipoOrden, paramValues, true, null));
		filteredQuery.append(DaoUtils.addFilter("S.COD_IDORDEN", "=", idOrden, paramValues, true, null));

		final Query q = em.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		final List<BigDecimal> datos = q.getResultList();
		if (CollectionUtils.isEmpty(datos)) {
			throw new ExcepcionEjecucionAplicacion(Errores_kyfb_servicios.ORDEN_SIN_FIRMA_O_INEXISTENTE);
		}
		return datos;
	}

	/**
	 * Find firmas realizas by num items.
	 *
	 * @param fichero the fichero
	 * @return the list
	 */
	@Override
	@Transactional(value="tlsb")
	public List<String> findFirmasRealizasByUsuario(final FicheroInfo fichero) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder("SELECT F.QNU_NUMITEM FROM TLSB.TTLSBFFS F ");
		filteredQuery.append(DaoUtils.addFilter("F.COD_CANALDI", "=", Integer.parseInt(fichero.getCodClienteCash().substring(0, 4)), paramValues, null, null));
		filteredQuery.append(DaoUtils.addFilter("F.COD_BANCOINT", "=", Integer.parseInt(fichero.getCodClienteCash().substring(4, 8)), paramValues, true, null));
		filteredQuery.append(DaoUtils.addFilter("F.COD_LOGON2", "=", fichero.getCodClienteCash().substring(8, 16), paramValues, true, null));
		filteredQuery.append(DaoUtils.addFilter("F.COD_BANCOPR", "=", fichero.getsBancoProducto(), paramValues, true, null));
		filteredQuery.append(DaoUtils.addFilter("F.COD_PRODSERV", "=", fichero.getsCodProducto(), paramValues, true, null));
		filteredQuery.append(DaoUtils.addFilter("F.COD_SUBPRODU", "=", fichero.getsCodSubproducto(), paramValues, true, null));
		filteredQuery.append(DaoUtils.addFilter("F.COD_USUARIO", "=", fichero.getsCodUsuario(), paramValues, true, null));
		filteredQuery.append(DaoUtils.addFilter("F.XSN_FIRMADO", "=", "S", paramValues, true, null));

		final Query q = emTLSB.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		// la lista puede devolverse vacia
		// DaoUtils.atLeastOneRecord(datos);

		//Cuando se solicita un unico elemento no se devuelve una lista de arrays si no una lista de objetos del tipo que sea
		return q.getResultList();
	}

	/**
	 * Find firmas realizas by num items.
	 *
	 * @param qnuItems the qnu items
	 * @return the list
	 */
	@Transactional(value="tlsb")
	private List<Object[]> findFirmasRealizasByNumItems(final BigDecimal[] qnuItems) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("SELECT VARCHAR(F.COD_USUARIO), VARCHAR(F.XTI_PODFIR) FROM TLSB.TTLSBFFS F ");
		filteredQuery.append(DaoUtils.addInClause("F.QNU_NUMITEM", qnuItems, paramValues, null, null));
		filteredQuery.append(DaoUtils.addFilter("F.XSN_FIRMADO", "=", "S", paramValues, true, null));

		final Query q = emTLSB.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		final List<Object[]> datos = q.getResultList();
		DaoUtils.atLeastOneRecord(datos);

		return datos;
	}

	/**
	 * Find usuarios numeros aleatorios by num items.
	 *
	 * @param qnuItems the qnu items
	 * @return the list
	 */
	@Override
	@Transactional(value="tlsb")
	public Map<String, String> findUsuariosNumAleatorio(final BigDecimal qnuItem, final String referencia) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final Map<String, String> resultado = new HashMap<String, String>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("SELECT VARCHAR(F.COD_USUARIO), VARCHAR(F.COD_NUMALEAT) FROM TLSB.TTLSBFFS F ");
		filteredQuery.append(DaoUtils.addFilter("F.QNU_NUMITEM", "=", qnuItem, paramValues, null, null));
		filteredQuery.append(DaoUtils.addFilter("F.COD_LOGON2", "=", referencia, paramValues, true, null));

		final Query q = emTLSB.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		final List<Object[]> datos = q.getResultList();

		for (final Object[] o : datos) {
			// mapeamos el ResultList a la estructura del map
			resultado.put(((String) o[0]).trim(), ((String) o[1]).trim());
		}

		return resultado;
	}

	@Override
	@Transactional(value="tlbh")
	public final List<String[]> findMensajeAceptacion(final String codAplicacion, final String[] arrCodTipoOrden) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("SELECT VARCHAR(PPA.XSN_MSGACP), VARCHAR(PPA.COD_MSGACP), VARCHAR(PPA.COD_OBJF) ");
		filteredQuery.append("FROM TLSB.TTLSBPPA PPA");
		filteredQuery.append(DaoUtils.addFilter("PPA.COD_APLICACI", "=", codAplicacion, paramValues, null, null));
		filteredQuery.append(DaoUtils.addInClause("PPA.COD_OBJF", arrCodTipoOrden, paramValues, true, null));

		final Query q = em.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);
		return DaoUtils.transLstArrObjToLstArrStr(q.getResultList());
	}

	@Override
	@Transactional(value="tlsb")
	public final List<String> findCodUsuFirmaPrevia(final String codTipoOrden, final String[] arrCodNameFrmts) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("SELECT DISTINCT VARCHAR(ONT.COD_USUARIO) ");
		filteredQuery.append("FROM TLSB.TTLSBONT ONT");
		filteredQuery.append(DaoUtils.addFilter("ONT.COD_CLASEORD", "=", codTipoOrden, paramValues, null, null));
		filteredQuery.append(DaoUtils.addInClause("ONT.COD_USUARIO", arrCodNameFrmts, paramValues, true, null));

		final Query q = em.createNativeQuery(filteredQuery.toString());

		DaoUtils.addQueryParams(paramValues, q);

		//Cuando se solicita un unico elemento no se devuelve una lista de arrays si no una lista de objetos del tipo que sea
		return q.getResultList();
	}

	@Override
	@Transactional(value="tlsb")
	public final List<String> findTipOrdFirmaPrevia(final String codNameFrmt, final String[] arrCodTipoOrden) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("SELECT DISTINCT VARCHAR(ONT.COD_CLASEORD) ");
		filteredQuery.append("FROM TLSB.TTLSBONT ONT ");
		filteredQuery.append(DaoUtils.addFilter("ONT.COD_USUARIO", "=",codNameFrmt, paramValues, null, null));
		filteredQuery.append(DaoUtils.addInClause("ONT.COD_CLASEORD", arrCodTipoOrden, paramValues, true, null));

		final Query q = em.createNativeQuery(filteredQuery.toString());

		DaoUtils.addQueryParams(paramValues, q);

		//Cuando se solicita un unico elemento no se devuelve una lista de arrays si no una lista de objetos del tipo que sea
		return q.getResultList();
	}

	/**
	 * Find usuarios numeros aleatorios by cod usuario.
	 *
	 * @param qnuItems the qnu items
	 * @return the list
	 */
	@Override
	@Transactional(value="tlsb")
	public Map<String, String> findFicherosNumAleatorio(final String codUsuario, final String referencia) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final Map<String, String> resultado = new HashMap<String, String>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("SELECT F.QNU_NUMITEM, VARCHAR(F.COD_NUMALEAT) FROM TLSB.TTLSBFFS F ");
		filteredQuery.append(DaoUtils.addFilter("F.COD_USUARIO", "=", codUsuario, paramValues, null, null));
		filteredQuery.append(DaoUtils.addFilter("F.COD_LOGON2", "=", referencia, paramValues, true, null));

		final Query q = emTLSB.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		final List<Object[]> datos = q.getResultList();

		for (final Object[] o : datos) {
			// mapeamos el ResultList a la estructura del map
			resultado.put(((BigDecimal) o[0]).toString(), ((String) o[1]).trim());
		}

		return resultado;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@Transactional(value="tlbh")
	public int countNumAuditoria(final String codClienteCash, final String tipoOrden, final String idOrden, final short codAccion) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("SELECT count(*) FROM TLSB.TTLSBFUA F ");
		filteredQuery.append(DaoUtils.addFilter("F.COD_CLIECASH", "=", codClienteCash, paramValues, null, null));
		filteredQuery.append(DaoUtils.addFilter("F.COD_CLASEORD", "=", tipoOrden, paramValues, true, null));
		filteredQuery.append(DaoUtils.addFilter("F.COD_IDORDEN", "=", idOrden, paramValues, true, null));
		filteredQuery.append(DaoUtils.addFilter("F.COD_ACCION", "=", codAccion, paramValues, true, null));

		final Query q = em.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		return ((Number)q.getSingleResult()).intValue();
	}

	/* (non-Javadoc)
	 * @see com.bbva.kyfb.kyfbdaofi.IFirmasDao#findTiposDeCambio(int)
	 */
	@Override
	@Transactional(value="tlsb")
	public Map<String, Double> findTiposDeCambio(final int codBancoInterno) {

		final Map<String, Double> tiposDeCambio = new HashMap<String, Double>();
		final StringBuilder filteredQuery = new StringBuilder();
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		List<Object[]> resultado = null;

		filteredQuery.append("SELECT VARCHAR(COD_DIISOALF), IMP_VENTEURO FROM TLSB.TTLSBCDD TTLSBCDD WHERE COD_BANCSB  = ?1 AND ");
		filteredQuery.append("COD_TIPOINF1  = 'DI' and FEC_CIERRE IN (SELECT MAX(FEC_CIERRE) FROM TLSB.TTLSBCDD ");
		filteredQuery.append("WHERE COD_BANCSB  = ?2 AND COD_TIPOINF1  = 'DI') ORDER BY COD_DIISOALF DESC");

		paramValues.put(1, codBancoInterno);
		paramValues.put(2, codBancoInterno);

		final Query q = emTLSB.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		resultado = q.getResultList();

		for (final Object[] o : resultado) {
			// mapeamos a la estructura del map acordada para las divisas [("EUR", 1.000), ("USD", 1.3700), ...]
			tiposDeCambio.put((String) o[0], ((BigDecimal) o[1]).doubleValue());
		}

		return tiposDeCambio;
	}

	/* (non-Javadoc)
	 * @see com.bbva.kyfb.kyfbdaofi.IFirmasDao#findCodServicioGlobal(int)
	 */
	@Override
	@Transactional(value="tlsb")
	public Map<String, String> findCodServicioGlobal(final int codBancoInterno) {

		final Map<String, String> codigosDeServicio = new HashMap<String, String>();
		final StringBuilder filteredQuery = new StringBuilder();
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		List<Object[]> resultado = null;

		filteredQuery.append("SELECT SPC.COD_SERCRUBD, SPC.COD_SERVICIO FROM BDCT.TBDCTSPC SPC WHERE SPC.COD_BANCOINT = ?1");

		paramValues.put(1, codBancoInterno);

		final Query q = emTLSB.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		resultado = q.getResultList();

		for (final Object[] o : resultado) {
			// mapeamos a la estructura del map acordada para los codigos de servicio [("233", "8233"), ("523", "8523"), ...]
			codigosDeServicio.put(((Short) o[1]).toString(), ((Short) o[0]).toString());
		}

		return codigosDeServicio;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void insertFRF(final Ttlsbfrf registroFirmado) {
		try {
			// Insertamos en la tabla FRF, si hay excepcion, se eleva a capas superiores
			registroFirmado.persist();
			registroFirmado.flush();
			LOG.info("ServicioFirmasDaoImpl.insertFRF - Se inserta correctamente en la FRF");
			//Si da error
			// el firmante existe para el fichero, por lo que es un fichero
			// antiguo y realizamos el update.
		} catch (final PersistenceException pe) {
			updateRegistroToFirmado(registroFirmado);
		} catch (final NonUniqueObjectException nuoe) {
			updateRegistroToFirmado(registroFirmado);
		} catch (final JpaSystemException jse) {
			updateRegistroToFirmado(registroFirmado);
		}
	}

	/**
	 * Update registro firmas host.
	 * @param registroFirmado
	 */
	@Transactional(value="tlsb")
	private void updateRegistroToFirmado(final Ttlsbfrf registroFirmado) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("UPDATE TLSB.TTLSBFRF SET XSN_FIRMADO = '" + registroFirmado.getXsnFirmado() + "', COD_NUMALEAT = '"+ registroFirmado.getCodNumaleat() +"' ");
		filteredQuery.append(DaoUtils.addFilter("TIM_FICHERO", "=", registroFirmado.getId().getTimFichero(), paramValues, null, null));
		filteredQuery.append(DaoUtils.addFilter("COD_CDNITR", "=", registroFirmado.getId().getCodDNITr(), paramValues, true, null));

		final Query q = emTLSB.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		final int resultado = q.executeUpdate();
		DaoUtils.oneRecordUpdated(resultado);

		LOG.info("ServicioFirmasDaoImpl.insertFRF - Se actualiza correctamente en la FRF");
	}


	/**
	 * {@inheritDoc}
	 */
	@Override
	public Map<String, String> findNumAleatorioFRFbyUsuario(final String documentoUsuario) {

		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final Map<String, String> resultado = new HashMap<String, String>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("SELECT VARCHAR(F.TIM_FICHERO), VARCHAR(F.COD_NUMALEAT) FROM TLSB.TTLSBFRF F ");
		filteredQuery.append(DaoUtils.addFilter("F.COD_CDNITR", "=", documentoUsuario, paramValues, null, null));

		final Query q = emTLSB.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		final List<Object[]> datos = q.getResultList();

		for (final Object[] o : datos) {
			// mapeamos el ResultList a la estructura del map
			String fechaCreacion;
			try {
				final Date parse = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").parse((String)o[0]);
				fechaCreacion = new SimpleDateFormat("yyyy-MM-dd-HH.mm.ss.SSS").format(parse);
				fechaCreacion = StringUtils.rightPad(fechaCreacion, Constants.FORMATO_TIMESTAMPSOLIC_MIN_LENGTH, '0');
			} catch (final ParseException e) {
				fechaCreacion = (String)o[0];
			}
			resultado.put(fechaCreacion, ((String) o[1]).trim());
		}

		return resultado;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Map<String, String> findNumAleatorioFRF(final String timFichero) {

		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final Map<String, String> resultado = new HashMap<String, String>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("SELECT VARCHAR(F.COD_CDNITR), VARCHAR(F.COD_NUMALEAT) FROM TLSB.TTLSBFRF F ");
		filteredQuery.append(DaoUtils.addFilter("F.TIM_FICHERO", "=", timFichero, paramValues, null, null));

		final Query q = emTLSB.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		final List<Object[]> datos = q.getResultList();

		for (final Object[] o : datos) {
			// mapeamos el ResultList a la estructura del map
			resultado.put(((String)o[0]).trim(), ((String) o[1]).trim());
		}

		return resultado;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@Transactional(value="tlsb")
	public void updateNumAleatorioFRF(final Ttlsbfrf firmante) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("UPDATE TLSB.TTLSBFRF SET COD_NUMALEAT = '"+ firmante.getCodNumaleat() +"'");
		filteredQuery.append(DaoUtils.addFilter("COD_CDNITR", "=", firmante.getId().getCodDNITr(), paramValues, null, null));
		filteredQuery.append(DaoUtils.addFilter("TIM_FICHERO", "=", firmante.getId().getTimFichero(), paramValues, true, null));

		final Query q = emTLSB.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		LOG.info("ServicioFirmasDaoImpl.updateNumAleatorioFRF - Se realiza el Update en la FRF");
		LOG.info("ServicioFirmasDaoImpl.updateNumAleatorioFRF - COD_CDNITR: " + paramValues.get(1));
		LOG.info("ServicioFirmasDaoImpl.updateNumAleatorioFRF - TIM_FICHERO: " + paramValues.get(2));

		final int resultado = q.executeUpdate();
		LOG.info("ServicioFirmasDaoImpl.updateNumAleatorioFRF - Registros actualizados: "+ resultado);
		DaoUtils.oneRecordUpdated(resultado);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	@Transactional(value="tlsb")
	public void deleteFirmantesFRF(final String nif, final Date ficheroBorrado) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		final String[] nifs = nif.split("\\|");

		if(nifs.length!=3 || nifs[0].isEmpty()) {
			throw new ExcepcionEjecucionAplicacion(Errores_kyfb_servicios.CAMPO_OBLIGATORIO_NO_INFORMADO);
		}

		filteredQuery.append("DELETE FROM TLSB.TTLSBFRF ");
		filteredQuery.append(DaoUtils.addFilter("COD_CDNITR", "=", nifs[0], paramValues, null, null));
		filteredQuery.append(DaoUtils.addFilter("TIM_FICHERO", "=", ficheroBorrado, paramValues, true, null));

		final Query q = emTLSB.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);
		q.executeUpdate();
		// Comentamos porque no hay que comprobar que el DELETE borre resultados
		// DaoUtils.oneRecordUpdated(resultado);
		emTLSB.flush();
	}

	@Override
	@Transactional(value="tlbh")
	public int countNumNotificacion(final String referencia, final String codUsuario, final String xsnAvisnoti) {
		final Map<Integer, Object> paramValues = new HashMap<Integer, Object>();
		final StringBuilder filteredQuery = new StringBuilder();

		filteredQuery.append("SELECT count(*) FROM TLWM.TTLWMTER T ");
		filteredQuery.append(DaoUtils.addFilter("T.COD_LOGONAPL", "=", referencia, paramValues, null, null));
		filteredQuery.append(DaoUtils.addFilter("T.COD_USUARIO", "=", codUsuario, paramValues, true, null));
		filteredQuery.append(DaoUtils.addFilter("T.XSN_AVISNOTI", "=", xsnAvisnoti, paramValues, true, null));

		final Query q = em.createNativeQuery(filteredQuery.toString());
		DaoUtils.addQueryParams(paramValues, q);

		return ((Number)q.getSingleResult()).intValue();
	}
}
